/*!
 * zeroGrid.js
 * http://git.oschina.net/cylansad/zeroGrid
 *
 * Copyright 2016, Sad
 */
(function(obj) {

    if (typeof module !== 'undefined' && typeof exports === 'object' && define.cmd) {
        module.exports = obj;
    } else if (typeof define === 'function' && define.amd) {
        define(function() {
            return obj;
        });
    } else {
        window.zeroGrid = obj;
    }

}((function($, undefined) {

    var zeroGrid = function(opt) {

        this.params = {
            container: '.zerogrid-container',
            columns: [], // 显示的列
            url: "", // 数据来源的URL
            pageIndex: 1, // 当前页
            pageSize: 20, // 每页显示的记录数
            pagination: true, // 是否需要分页
            paginationStyle: 'full', // 分页样式，full/simple
            checkboxProperty: undefined, // 复选框对应的属性
            checkboxPropertyFunc: undefined, // 控制每条记录的复选框是否需要显示的function
            radioboxProperty: undefined,
            radioboxPropertyFunc: undefined,
            formId: "",
            loadBeforeListener: undefined,
            loadAfterListener: undefined,
            renderBeforeListener: undefined,
            renderAfterListener: undefined,
            unique: getUuid(), // 唯一的ID，建议使用提供的默认值
            datas: []
        };

        // 临时数据
        this.tempData = {
            pageTotalSize: 1, // 总页数
            sortField: '',
            sortOrder: '',
            isloading: false, // 是否正在加载数据中，用于防止过快重复加载数据
            datas: []
        };

        this.init(opt);
    };

    zeroGrid.prototype = {

        /**
         * 初始化参数
         * @param  {[type]} opt [description]
         * @return {[type]}     [description]
         */
        init: function(opt) {
            $.extend(this.params, opt);

            if (typeof this.params.url === 'undefined' || this.params.url === '') {
                if (typeof this.params.datas !== 'undefined') {
                    this.tempData.datas = this.params.datas;
                }
            }
        },

        /**
         * 渲染组件
         * @return {[type]} [description]
         */
        render: function() {
            if (this.params.renderBeforeListener !== undefined) {
                this.params.renderBeforeListener(this.params);
            }
            this.renderTable();
            if (this.params.renderAfterListener !== undefined) {
                this.params.renderAfterListener(this.params);
            }
            this.load();
        },

        /**
         * 渲染表格
         * @return {[type]} [description]
         */
        renderTable: function() {
            var html = '<div id="waitDiv_' + this.params.unique + '" class="ui_grid_loading"></div>';
            html += '   <table class="zero-grid zero-grid-hover" id="table_' + this.params.unique + '" table-unique="' + this.params.unique + '">';
            html += '       <thead>';
            html += '           <tr>';

            // 是否显示checkbox
            if (typeof this.params.checkboxProperty !== 'undefined' || typeof this.params.radioboxProperty !== 'undefined') {
                html += '           <th style="text-align:center;width:30px;padding-left:0">';
                if (typeof this.params.checkboxProperty !== 'undefined') {
                    html += '           <input id="checkboxAll_' + this.params.unique + '" type="checkbox" />';
                }
                html += '          </th>';
            }

            // 显示列
            for (var i = 0; i < this.params.columns.length; i++) {
                var col = this.params.columns[i];
                html += '<th';
                if (col.width !== undefined) {
                    html += ' width="' + col.width + '"';
                }
                html += '>';

                if (col.sort !== undefined) {
                    html += '<a class="ui_grid_sort_default" role="sort" sort="' + col.sort + '" title="点击按[' + col.display.replace('<br>', '') + ']排序">' + col.display + '</a>';
                } else {
                    html += col.display;
                }

                html += '</th>';
            }
            html += '           </tr>';
            html += '       </thead>';
            html += '       <tbody id="tbody_' + this.params.unique + '" style="font-size:12px;"></tbody>';
            html += '   </table>';

            html += '   <div id="pagination_' + this.params.unique + '" class="zero-grid-pagination-d"></div>';
            $(this.params.container).html(html);

            this.bindTableEvent();
        },

        /**
         * 加载数据
         * @param  {[type]} pageIndex [description]
         * @param  {[type]} params    [description]
         * @return {[type]}           [description]
         */
        load: function(pageIndex, params) {
            // 检查是否正在加载数据中，如果正在加载中，则阻断后续的加载请求
            if (this.loading) return;
            this.loading = true;

            this.openWaitDiv();
            this.resetCheckboxStatus();

            if (pageIndex !== undefined) {
                this.params.pageIndex = pageIndex;
            }
            var _this = this;

            // 查询前
            if (this.params.loadBeforeListener != null) this.params.loadBeforeListener();

            // 如果url不为空则从后台获取数据
            if (typeof this.params.url !== 'undefined' && this.params.url !== '') {
                var postDataStr = $("#" + this.params.formId).serialize() + "&pageIndex=" + this.params.pageIndex + "&pageSize=" + this.params.pageSize + "&sortField=" + this.tempData.sortField + "&sortOrder=" + this.tempData.sortOrder;
                if (params !== undefined) {
                    postDataStr += "&" + _params;
                }

                $.ajax({
                    url: this.params.url + (this.params.url.indexOf('?') !== -1 ? '&' : '?') + '_=' + new Date().getTime(),
                    dataType: 'json',
                    data: postDataStr,
                    type: 'post',
                    error: function() { console.log("数据加载异常！请检查是否登录超时。"); },
                    success: function(data) {
                        data.pageIndex = parseInt(data.pageIndex);
                        data.pageSize = parseInt(data.pageSize);
                        data.total = parseInt(data.total);
                        _this.tempData.datas = data.datas;
                        _this.renderData(data);
                    }
                });
            } else {
                // 从前台取数据
                var data = {
                    total: this.tempData.datas.length,
                    pageIndex: this.params.pageIndex,
                    pageSize: this.params.pageSize,
                    datas: this.params.pagination ? getDatasByPartition(this.tempData.datas, this.params.pageIndex, this.params.pageSize) : this.tempData.datas
                };
                this.renderData(data);
            }
        },

        /**
         * 渲染数据
         * @param  {[type]} data [description]
         * @return {[type]}      [description]
         */
        renderData: function(data) {
            var html = '';
            if (data.datas.length > 0) {
                for (var i = 0; i < data.datas.length; i++) {
                    html += '<tr>';

                    // 判断是否需要显示checkbox或radiobox
                    if (typeof this.params.checkboxProperty !== 'undefined') {
                        html += '<td style="text-align:center;padding-left:0">';
                        if (typeof this.params.checkboxPropertyFunc === 'undefined' || this.params.checkboxPropertyFunc(data[i])) {
                            html += '<input type="checkbox" name="box_' + this.params.unique + '" value="' + getVal(this.params.checkboxProperty, data.datas[i]) + '" />';
                        }
                        html += '</td>';
                    } else if (typeof this.params.radioboxProperty !== 'undefined') {
                        html += '<td style="text-align:center;padding-left:0">';
                        if (typeof this.params.radioboxPropertyFunc === 'undefined' || this.params.radioboxPropertyFunc(data[i])) {
                            html += '<input type="radio" name="box_' + this.params.unique + '" value="' + getVal(this.params.radioboxProperty, data.datas[i]) + '" />';
                        }
                        html += '</td>';
                    }

                    // 循环显示数据
                    for (var j = 0; j < this.params.columns.length; j++) {
                        html += '<td>';

                        // 如果设置view属性，则显示view属性里面的内容，没有则根据property显示属性
                        var _content = '';
                        if (this.params.columns[j].view != undefined) {
                            if (typeof(this.params.columns[j].view) == 'function') {
                                _content = this.params.columns[j].view(data.datas[i]);
                            } else {
                                _content = convertHtmlProp(this.params.columns[j].view, data.datas[i]);
                            }
                        } else {
                            // 根据property显示属性
                            _content = getVal(this.params.columns[j].property, data.datas[i]);
                        }
                        html += _content + '</td>';
                    }
                }
            } else {
                var colLength = this.params.columns.length + (this.hasBox() ? 1 : 0);
                html += '<tr><td style="text-align:center;" colspan="' + colLength + '">没有数据显示！</td></tr>';
            }
            $('#tbody_' + this.params.unique).html(html);

            // 构建分页信息
            if (this.params.pagination) {
                // 获取总页数
                this.tempData.pageTotalSize = Math.ceil(data.total / data.pageSize);
                if (isNaN(this.tempData.pageTotalSize)) {
                    return;
                }
                // 获取分页的项目
                var totalPageItems = [];
                var startIndex = Math.floor((data.pageIndex - 1) / 5) * 5;
                for (var i = 1; i <= 5; i++) {
                    var index = startIndex++ + 1;
                    if (index <= this.tempData.pageTotalSize) { totalPageItems.push(index); }
                }

                var phtml = '<ul class="zero-grid-pagination" style="margin:0px!important">';
                phtml += '<li><a title="Go最前页" role="goFirstPage" href="javascript:void(0)">««</a></li>';
                phtml += '<li><a title="Go上一页" role="goPreviousPage" href="javascript:void(0)">«</a></li>';
                for (var i = 0; i < totalPageItems.length; i++) {
                    phtml += '<li';
                    if (totalPageItems[i] == data.pageIndex) phtml += ' class="active"';

                    phtml += '><a href="javascript:void(0)" role="goPageIndex" pageindex="' + totalPageItems[i] + '" title="Go第' + totalPageItems[i] + '页">' + totalPageItems[i] + '</a></li>';
                }
                phtml += '<li><a title="Go下一页" role="goNextPage" href="javascript:void(0)">»</a></li>';
                phtml += '<li><a title="Go最后页" role="goLastPage" href="javascript:void(0)">»»</a></li>';
                if (this.params.paginationStyle === 'full') {
                    phtml += '<div class="zero-grid-pagination-des">共' + data.total + '条数据，分' + this.tempData.pageTotalSize + '页显示，';
                    phtml += this.buildPageSizeSelect() + '</div>';
                }
                $("#pagination_" + this.params.unique).html(phtml);
            }

            // 绑定事件
            this.bindLoadEvent();
            // 关闭等待
            this.closeWaitDiv();

            // 查询后
            if (this.params.loadAfterListener != null) this.params.loadAfterListener();
            this.loading = false;
        },

        // 构建每页多少条的下拉框代码
        buildPageSizeSelect: function() {
            var pageSize = this.params.pageSize;
            var html = '每页显示<select role="goPageSize" class="zero-grid-pagination-pz">';
            html += '<option value="10" ' + ((pageSize == 10 ? 'selected=selected' : '')) + '>10</option>';
            html += '<option value="20" ' + ((pageSize == 20 ? 'selected=selected' : '')) + '>20</option>';
            html += '<option value="30" ' + ((pageSize == 30 ? 'selected=selected' : '')) + '>30</option>';
            html += '<option value="40" ' + ((pageSize == 40 ? 'selected=selected' : '')) + '>40</option>';
            html += '<option value="50" ' + ((pageSize == 50 ? 'selected=selected' : '')) + '>50</option>';
            html += '<option value="100" ' + ((pageSize == 100 ? 'selected=selected' : '')) + '>100</option>';
            html += '</select>条数据。';
            return html;
        },

        // 打开等待的遮罩层
        openWaitDiv: function() {
            var waitDivObj = $("#waitDiv_" + this.params.unique);
            var gridLeft = $("#table_" + this.params.unique).position().left;
            var gridTop = $("#table_" + this.params.unique).position().top;
            var gridWidth = $("#table_" + this.params.unique).width();
            var gridHeight = $("#table_" + this.params.unique).height();

            waitDivObj.css({ position: "absolute", /*left: gridLeft, top: gridTop,*/ width: gridWidth, height: gridHeight, display: "block" });
        },

        // 关闭等待的遮罩层
        closeWaitDiv: function() {
            $("#waitDiv_" + this.params.unique).css({ display: "none" });
        },

        /**
         * 表格渲染出来后绑定的事件
         */
        bindTableEvent: function() {
            var _this = this;

            // checkbox全选
            $('#checkboxAll_' + this.params.unique).click(function() {
                var _checked = this.checked;
                var checkboxs = document.getElementsByName('box_' + _this.params.unique);
                for (var i = 0; i < checkboxs.length; i++) {
                    checkboxs[i].checked = _checked;
                }
            });

            // 点击行选中checkbox或radiobox
            $("#table_" + this.params.unique).on("click", "td", function() {
                //console.log($(this).parent().find('input[type="radio"]')[0]);
            });
        },

        /**
         * 加载数据后绑定的事件
         */
        bindLoadEvent: function() {
            var _this = this;
            var dom = $(this.params.container);

            // 最前页事件
            dom.find("a[role='goFirstPage']").click(function() {
                _this.params.pageIndex = 1;
                _this.load();
            });

            //上一页事件
            dom.find("a[role='goPreviousPage']").click(function() {
                var previousPageIndex = _this.params.pageIndex - 1;
                if (previousPageIndex <= 0) previousPageIndex = 1;
                _this.params.pageIndex = previousPageIndex;
                _this.load();
            });

            // 下一页事件
            dom.find("a[role='goNextPage']").click(function() {
                var nextPageIndex = _this.params.pageIndex + 1;
                if (nextPageIndex > _this.tempData.pageTotalSize) nextPageIndex = _this.tempData.pageTotalSize;
                _this.params.pageIndex = nextPageIndex;
                _this.load();
            });

            // 最后页事件
            dom.find("a[role='goLastPage']").click(function() {
                _this.params.pageIndex = _this.tempData.pageTotalSize;
                _this.load();
            });

            // 指定跳转到第几页事件
            dom.find("a[role='goPageIndex']").click(function() {
                _this.params.pageIndex = parseInt($(this).attr("pageindex"));
                _this.load();
            });

            // 指定每页显示的条数
            dom.find("select[role='goPageSize']").change(function() {
                _this.params.pageSize = parseInt(this.value);
                _this.params.pageIndex = 1;
                _this.load();
            });

            // 排序的事件
            dom.find("a[role='sort']").unbind("click"); // 由于每次刷新表格数据都会重新绑定该事件，导致事件重复，因此需要先移除前面的事件再进行绑定
            dom.find("a[role='sort']").click(function() {
                _this.resetSortClass();
                var sField = $(this).attr("sort");
                $(this).removeClass();
                if (_this.tempData.sortField == sField) {
                    if (_this.tempData.sortOrder == null || _this.tempData.sortOrder == "") {
                        _this.tempData.sortOrder = "asc";
                        $(this).addClass("ui_grid_sort_asc");
                    } else if (_this.tempData.sortOrder == "asc") {
                        _this.tempData.sortOrder = "desc";
                        $(this).addClass("ui_grid_sort_desc");
                    } else {
                        _this.tempData.sortOrder = "asc";
                        $(this).addClass("ui_grid_sort_asc");
                    }
                } else {
                    _this.tempData.sortOrder = "asc";
                    $(this).addClass("ui_grid_sort_asc");
                }
                _this.tempData.sortField = sField;
                _this.params.pageIndex = 1;
                _this.load();
            });
        },

        // 重置全选checkbox的状态
        resetCheckboxStatus: function() {
            $('#checkboxAll_' + this.params.unique).attr("checked", false);
        },

        // 是否需要显示checkbox或radiobox
        hasBox: function() {
            return this.params.checkboxProperty !== undefined || this.params.radioboxProperty !== undefined;
        },

        // 重置排序的样式
        resetSortClass: function() {
            $("#table_" + this.params.unique).find("a[role='sort']").each(function(i) {
                $(this).removeClass();
                $(this).addClass("ui_grid_sort_default");
            });
        },

        // 获取选择的值
        getSelectedVal: function() {
            var vals = '';
            var boxes = document.getElementsByName('box_' + this.params.unique);
            for (var i = 0; i < boxes.length; i++) {
                var box = boxes[i];
                if (box.checked) {
                    if (vals != '') {
                        vals += ',';
                    }
                    vals += box.value;
                }
            }
            return vals;
        },

        // 获取当前表格所有数据
        getDatas: function() {
            return this.tempData.datas;
        },

        // 根据属性名和值获取当前表格对应的数据
        getDatasByProperty: function(vals, property) {
            var datas = [];
            var valsArr = vals.split(',');
            for (var i = 0; i < valsArr.length; i++) {
                for (var j = 0; j < this.tempData.datas.length; j++) {
                    var val = getVal(property, this.tempData.datas[j]);
                    if (val === valsArr[i]) {
                        datas.push(this.tempData.datas[j]);
                        break;
                    }
                }
            }
            return datas;
        }
    };

    /**
     * 获取uuid
     * @returns {string}
     */
    function getUuid() {
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4";
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
        s[8] = s[13] = s[18] = s[23] = "";
        return s.join("");
    }

    /**
     * 根据属性名从对象中找到对应的值
     * @param propName
     * @param dataObj
     * @returns {*}
     */
    function getVal(propName, dataObj) {
        for (var prop in dataObj) {
            if (prop == propName) {
                return dataObj[prop] || '';
            }
        }
    }

    /**
     * 模板解析
     * @param  {[type]} template [description]
     * @param  {[type]} context  [description]
     * @return {[type]}          [description]
     */
    function convertHtmlProp(template, context) {
        var tokenReg = /(\\)?\{{([^\{\}\\]+)(\\)?\}}/g;
        return template.replace(tokenReg, function(word, slash1, token, slash2) {
            if (slash1 || slash2) {
                return word.replace('\\', '');
            }
            var variables = token.replace(/\s/g, '').split('.');
            var currentObject = context;
            var i, length, variable;
            for (i = 0; i < variables.length; i++) {
                variable = variables[i];
                currentObject = currentObject[variable];
                if (currentObject === undefined || currentObject === null) return '';
            }
            return currentObject;
        });
    }

    /**
     * 获取分页后的数据
     * @param  {[type]} datas     [description]
     * @param  {[type]} pageIndex [description]
     * @param  {[type]} pageSize  [description]
     * @return {[type]}           [description]
     */
    function getDatasByPartition(datas, pageIndex, pageSize) {
        var res = [];
        for (var i = (pageIndex - 1) * pageSize; i < pageIndex * pageSize; i++) {
            if (datas[i] !== undefined) {
                res.push(datas[i]);
            }
        }
        return res;
    }

    return zeroGrid;

}(jQuery))));
